package com.data.hijack.protocol.executor;

import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import com.data.hijack.analysis.Proccessor;
import com.data.hijack.constant.Constants;
import com.data.hijack.context.HolderContext;
import com.data.hijack.service.SysConfig;
import com.data.hijack.util.*;

/**
 * @author husq
 */
public abstract class AbstractSchemaExecutor {
    private static final Logger logger = Logger.getLogger(AbstractSchemaExecutor.class);

    private SysConfig sysConfig;
    protected Selector selector;

    public void execute(Selector selector, SelectionKey selectionKey, SysConfig sysConfig) throws Exception {
        this.selector = selector;
        this.sysConfig = sysConfig;
        try {
            this.execute(selectionKey);
        } catch (Exception e) {
            TimeUnit.SECONDS.sleep(1);
            this.closeChannel((SocketChannel)selectionKey.attachment());
            throw new Exception(e);
        }
    }

    protected abstract void execute(SelectionKey selectionKey) throws Exception;

    protected String fire(String msg) throws Exception {
        if (StringUtils.isBlank(msg)) {
            return msg;
        }

        this.printMsg(msg, "Source message");

        String sendedMsg = this.analysisMessage(msg);

        this.printMsg(sendedMsg, "Converted message");

        return sendedMsg;
    }

    private String analysisMessage(String src) throws Exception {
        String isInterceptable = this.getSysConfig().getIsInterceptable();
        if (Constants.IS_INTERCEPTABLE_0.equals(isInterceptable)) {
            String mode = this.getSysConfig().getMode();
            String proccessor = this.getSysConfig().getProccessor();
            String cp = "";
            if (Constants.MODE_1.equals(mode)) {
                cp = Constants.TEMPLATE_PROCCESSOR;
            } else if (Constants.MODE_2.equals(mode)) {
                Asserts.notBlank(proccessor, "Configuration proccessor");
                cp = proccessor.trim();
            }
            Proccessor proc = BeanUtils.instantiateClass(cp);
            Asserts.notNull(proc, "Proccessor instance");

            String bizNameInPlugin = (String)HolderContext.get(Constants.BIZ_NAME_IN_PLUGIN);
            String analMsg = proc.proccess(src, this.getSysConfig().getSysConfig(), bizNameInPlugin);
            String sendedMsg =
                Constants.IS_TRANSLATABLE_1.equalsIgnoreCase(this.getSysConfig().getIsTranslatable()) ? analMsg : src;

            return sendedMsg;
        }

        return src;
    }

    protected void closeChannel(SocketChannel channel) {
        AppUtils.closeChannel(channel, this.selector);
    }

    protected SysConfig getSysConfig() {
        return this.sysConfig;
    }

    private void printMsg(Object msg, String desc) {
        if (this.getSysConfig().getLogMessage()) {
            logger.warn(TextUtils.format("%s【%s】", desc, msg));
        }
    }

}
